from PyQt4 import QtCore, QtGui


try:
    xrange
except NameError:
    xrange = range


def create_action(parent=None, text=None, icon=None,
                  slot=None, signal='triggered()', shortcut=None,
                  checkable=False, status_tip=None, tool_tip=None, whats_this=None,
                  data=None, propagate_tips=True, has_data=False):
    '''Creates a `QAction` with the given informations.

    The parameters are:

        + *parent* a `QObject` or `None`(default).
          The parent object of the `QAction`.

        + *text* the `QAction`s text as string or `QString`.

        + *icon* the `QAction`s icon as `QIcon`.

        + *slot* the slot that should be called when *signal*
          is sent.

        + *signal* the name of the signal that should "trigger" the slot.
          Default to "triggered()".

        + *shortcut* the `QAction`s shortcut as string or `QKeySequence`,

        + *checkable*, if `True` makes the `QAction` be checkable.

        + *status_tip* the status trip of the `QAction` as string.

        + *tool_tip* the tool tip of the `QAction` as string.

        + *whats_this* the whats this of the `QAction` as string.

        + *data* the `QAction`s data.

        + *propagate_tips* if this parameter is `True`,
          the tips not provided will default to the value of the
          other tips.
          For example passing only *tool_tip* will cause
          *status_tip* and *whats_this* to default to *tool_tip*.

        + *has_data*, if this parameter is `True`,
          that the *data* parameter is taken as data even
          if it is `None`.
    '''

    if text is None and icon is None:
        action = QtGui.QAction(parent)
    elif text is not None:
        action = QtGui.QAction(text, parent)
    else:
        action = QtGui.QAction(icon, text, parent)

    if not propagate_tips:
        if status_tip is not None:
            action.setStatusTip(status_tip)
        if tool_tip is not None:
            action.setToolTip(tool_tip)
        if whats_this is not None:
            action.setWhatsThis(whats_this)
    else:
        if any((status_tip, tool_tip, whats_this)):
            if status_tip is None and tool_tip is None:
                status_tip = tool_tip = whats_this
            elif tool_tip is None and whats_this is None:
                tool_tip = whats_this = status_tip
            elif status_tip is None and whats_this is None:
                status_tip = whats_this = tool_tip
            elif tool_tip is None:
                tool_tip = status_tip
            elif status_tip is None:
                status_tip = tool_tip
            elif whats_this is None:
                whats_this = tool_tip

            action.setStatusTip(status_tip)
            action.setToolTip(tool_tip)
            action.setWhatsThis(whats_this)

    if data is not None or has_data:
        data = QtCore.QVariant(data)
        action.setData(data)

    if shortcut is not None:
        action.setShortcut(shortcut)

    if slot is not None:
        action.connect(action, QtCore.SIGNAL(signal), slot)

    if checkable:
        action.setCheckable(True)

    return action


def add_separator(widget):
    '''Adds a separator to the widgets actions.

    This function does not require the `addSeparator` method.
    '''

    try:
        widget.addSeparator()
    except AttributeError:
        action = QtGui.QAction(widget)
        action.setSeparator(True)
        widget.addAction(action)


def add_actions(widget, actions):
    '''Adds *actions* to *widget*.

    The *actions* parameter should be an iterable of `QAction`s
    and/or `None`s.

    `None`s are replaced by separators.
    '''

    for action in actions:
        if action is None:
            add_separator(widget)
        else:
            widget.addAction(action)


def widget_iterator(widget, start=None, stop=None, step=None,
                    item_func=None):
    '''An iterator over the items of *widget*.
    
    The three parameters *start*, *stop* and *step* have the
    same meaning as in the `range` function.
    
    If *stop* is `None` than the result of *widget.count()*
    is used.
    
    The *item_func* should be a function accepting *widget*
    as first parameter and an integer as the second parameter
    and it should return the item at the given index.
    It defaults to `None`, which means to use the *widget*.item
    method.
    '''
    
    if stop is None:
        stop = widget.count()
    
    indexes = xrange(start, stop, step)
    if item_func is None:
        for index in indexes:
            yield widget.item(index)
    else:
        for index in indexes:
            yield item_func(widget, index)